package com.baoyouqun.service.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.tree.Tree;
import cn.hutool.core.lang.tree.TreeNode;
import cn.hutool.core.lang.tree.TreeUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.baoyouqun.domain.Enum.DemandTypeEnum;
import com.baoyouqun.domain.VO.UserVO;
import com.baoyouqun.entity.City;
import com.baoyouqun.mapper.CityMapper;
import com.baoyouqun.mapper.UserVipTimeMapper;
import com.baoyouqun.service.CityService;
import com.baoyouqun.service.DemandService;
import com.baoyouqun.service.UserService;
import jakarta.annotation.Resource;
import okhttp3.*;
import org.apache.commons.lang3.StringUtils;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;

import java.io.IOException;
import java.math.BigDecimal;
import java.math.RoundingMode;
import java.util.*;
import java.util.stream.Collectors;


@Service
public class CityServiceImpl extends ServiceImpl<com.baoyouqun.mapper.CityMapper, City> implements CityService {

    // 腾讯LBS附近搜索API地址
    private static final String LBS_NEARBY_URL = "https://apis.map.qq.com/ws/geodata/v1/entity/nearby";
    private final String lbsKey = "你的腾讯LBS密钥";
    //    private final TencentIMService imService; // 腾讯IM服务封装类

    @Resource
    private CityMapper cityMapper;
    @Resource
    private UserVipTimeMapper userVipTimeMapper;
    @Resource
    private UserService userService;
    @Lazy
    @Resource
    private DemandService demandService;

    @Override
    public List<String> getSingleWithChildren(String code) {
        return cityMapper.getCodeAndAllChildren(code);
    }

    // 多个编码查询
    @Override
    public List<String> getMultiWithChildren(List<String> codes) {
        return cityMapper.getCodesAndAllChildren(codes);
    }

    @Override
    public List<Tree<String>> getTree() {
        List<City> list = list();
        List<TreeNode<String>> nodeList = CollUtil.newArrayList();
        list.forEach(r -> {
            TreeNode<String> node = new TreeNode<>(r.getCode(), r.getParentCode(), r.getName(), Long.parseLong(r.getCode()));
            nodeList.add(node);
        });
        return TreeUtil.build(nodeList, null);
    }

    @Override
    public List<Tree<String>> treeUserCount() {
        // 1. 获取所有地区数据
        List<City> allAreas = list();
        if (CollUtil.isEmpty(allAreas)) {
            return CollUtil.newArrayList();
        }

        // 2. 计算所有地区的用户数（含汇总逻辑）
        Map<String, Long> areaUserCountMap = calculateAreaUserCount(allAreas);

        // 3. 构建TreeNode列表并设置用户数
        List<TreeNode<String>> nodeList = buildTreeNodeList(allAreas, areaUserCountMap);

        // 4. 构建树形结构
        return TreeUtil.build(nodeList, null);
    }

    @Override
    public List<Tree<String>> treeDemandCount() {
        // 1. 获取所有地区数据
        List<City> allAreas = list();
        if (CollUtil.isEmpty(allAreas)) {
            return CollUtil.newArrayList();
        }

        // 2. 计算所有地区的发帖数（含汇总逻辑）
        Map<String, Long> areaDemandCountMap = calculateAreaDemandCount(allAreas);

        // 3. 构建TreeNode列表并设置发帖数
        List<TreeNode<String>> nodeList = buildTreeNodeDemandList(allAreas, areaDemandCountMap);

        // 4. 构建树形结构
        return TreeUtil.build(nodeList, null);
    }

    @Override
    public List<Tree<String>> treeUserVipCount(Long nationwideTotalUser) {
        // 1. 获取所有地区数据
        List<City> allAreas = list();
        if (CollUtil.isEmpty(allAreas)) {
            return CollUtil.newArrayList();
        }

        // 2. 计算所有地区的用户数和VIP数（含汇总逻辑）
        Map<String, Long> areaUserCountMap = calculateAreaUserCount(allAreas);
        Map<String, Long> areaUserVipCountMap = calculateAreaUserVipCount(allAreas);

        // 3. 缓存各省用户总数（用于市/县级百分比计算）
        Map<String, Long> provinceTotalMap = buildProvinceTotalMap(allAreas, areaUserCountMap);

        // 4. 构建TreeNode列表（包含百分比计算）
        List<TreeNode<String>> nodeList = buildTreeNodeVipList(
                allAreas,
                areaUserCountMap,
                areaUserVipCountMap,
                provinceTotalMap,
                nationwideTotalUser
        );

        // 5. 构建树形结构
        return TreeUtil.build(nodeList, null);
    }


    /**
     * 构建省份用户总数缓存（用于快速查询市/县级的父省总用户数）
     */
    private Map<String, Long> buildProvinceTotalMap(List<City> allAreas, Map<String, Long> areaUserCountMap) {
        Map<String, Long> provinceTotalMap = new HashMap<>();

        // 筛选所有省级节点
        List<String> provinceCodes = allAreas.stream()
                .filter(area -> StringUtils.isBlank(area.getParentCode())
                        || !existsInAreaCodes(allAreas, area.getParentCode()))
                .map(City::getCode)
                .collect(Collectors.toList());

        // 缓存各省用户总数
        for (String provinceCode : provinceCodes) {
            provinceTotalMap.put(provinceCode, areaUserCountMap.getOrDefault(provinceCode, 0L));
        }

        return provinceTotalMap;
    }

    /**
     * 判断编码是否存在于地区编码中（用于识别省级节点）
     */
    private boolean existsInAreaCodes(List<City> allAreas, String code) {
        return allAreas.stream().anyMatch(area -> code.equals(area.getCode()));
    }


    /**
     * 计算所有地区的用户数（核心修正：处理多结果集）
     */
    private Map<String, Long> calculateAreaUserCount(List<City> allAreas) {
        // 构建地区编码→地区对象的映射
        Map<String, City> areaMap = allAreas.stream()
                .collect(Collectors.toMap(City::getCode, area -> area));

        // 构建所有地区编码集合（用于设置默认值0）
        Set<String> allAreaCodes = allAreas.stream()
                .map(City::getCode)
                .collect(Collectors.toSet());

        // 2. 从用户表统计（修正：用List接收多条记录）
        List<Map<String, Object>> userAreaList = userService.countByAreaCodes();
        // 转换为Map<String, Long>（核心修正：手动处理多结果）
        Map<String, Long> userAreaCount = new HashMap<>();
        for (Map<String, Object> item : userAreaList) {
            // 从Map中取出地区编码和计数（注意类型转换）
            String cityCode = (String) item.get("cityCode");
            Long count = ((Number) item.get("count")).longValue(); // 兼容Integer/Long/BigDecimal
            userAreaCount.put(cityCode, count);
        }

        // 3. 为所有地区设置默认值0（无用户的地区也会有计数）
        Map<String, Long> allAreaUserCount = new HashMap<>(allAreaCodes.size());
        for (String areaCode : allAreaCodes) {
            allAreaUserCount.put(areaCode, userAreaCount.getOrDefault(areaCode, 0L));
        }

        // 4. 筛选区县编码（通过编码长度判断，示例：6位为区县）
        List<String> countyCodes = allAreas.stream()
                .filter(area -> isCounty(area.getCode()))
                .map(City::getCode)
                .collect(Collectors.toList());

        // 5. 向上汇总：区县→市→省
        for (String countyCode : countyCodes) {
            Long count = allAreaUserCount.get(countyCode);
            String parentCode = areaMap.get(countyCode).getParentCode();
            accumulateToParent(parentCode, count, areaMap, allAreaUserCount);
        }

        return allAreaUserCount;
    }

    /**
     * 计算各地区不同类型的需求数量（含汇总逻辑）
     */
    /**
     * 计算各地区不同类型的需求数量（含汇总逻辑）
     */
    private Map<String, Map<String, Long>> calculateAreaDemandByType(List<City> allAreas) {
        // 1. 构建地区编码映射
        Map<String, City> areaMap = allAreas.stream()
                .collect(Collectors.toMap(City::getCode, area -> area));

        // 2. 获取按地区和类型统计的原始数据
        List<Map<String, Object>> demandList = demandService.countByAreaAndType();

        // 3. 转换为双层Map结构：areaCode -> {type: count}
        Map<String, Map<String, Long>> demandTypeMap = new HashMap<>();

        // 初始化所有地区的统计数据
        for (City area : allAreas) {
            demandTypeMap.put(area.getCode(), new HashMap<>());
        }

        // 填充统计数据
        for (Map<String, Object> item : demandList) {
            String cityCode = (String) item.get("cityCode");
            DemandTypeEnum type = DemandTypeEnum.valueOfDbValue((String) item.get("type"));  // 假设type是Integer类型
            Long count = ((Number) item.get("count")).longValue();

            // 确保地区存在
            if (demandTypeMap.containsKey(cityCode)) {
                demandTypeMap.get(cityCode).put(type.getName(), count);
            }
        }

        // 4. 处理父节点汇总（递归汇总子节点的同类型数量）
        for (City area : allAreas) {
            String parentCode = area.getParentCode();
            if (StringUtils.isNotBlank(parentCode) && demandTypeMap.containsKey(parentCode)) {
                // 获取当前节点的类型统计
                Map<String, Long> currentTypeCount = demandTypeMap.get(area.getCode());
                // 获取父节点的类型统计
                Map<String, Long> parentTypeCount = demandTypeMap.get(parentCode);

                // 汇总到父节点
                for (Map.Entry<String, Long> entry : currentTypeCount.entrySet()) {
                    String type = entry.getKey();
                    long count = entry.getValue();
                    parentTypeCount.put(type, parentTypeCount.getOrDefault(type, 0L) + count);
                }
            }
        }

        return demandTypeMap;
    }

    /**
     * 构建包含分类型统计的树形节点列表
     */
    private List<TreeNode<String>> buildDemandTypeTreeNodeList(
            List<City> allAreas,
            Map<String, Map<String, Long>> demandTypeMap) {

        List<TreeNode<String>> nodeList = new ArrayList<>(allAreas.size());

        for (City area : allAreas) {
            TreeNode<String> node = new TreeNode<>(
                    area.getCode(),
                    area.getParentCode(),
                    area.getName(),
                    Integer.parseInt(area.getCode())
            );

            // 构建额外信息，包含两种类型的数量
            Map<String, Object> extra = new HashMap<>();
            Map<String, Long> typeCount = demandTypeMap.get(area.getCode());

            // 发布需求数量（假设type=1）
            extra.put("publishDemandCount", typeCount.getOrDefault(1, 0L));
            // 发布资源数量（假设type=2）
            extra.put("publishResourceCount", typeCount.getOrDefault(2, 0L));

            node.setExtra(extra);
            nodeList.add(node);
        }

        return nodeList;
    }

    /**
     * 构建分类型统计的树形结构
     */
    @Override
    public List<Tree<String>> treeDemandCountByType() {
        // 1. 获取所有地区数据
        List<City> allAreas = list();
        if (CollUtil.isEmpty(allAreas)) {
            return CollUtil.newArrayList();
        }

        // 2. 计算所有地区的分类型需求数量（含汇总逻辑）
        Map<String, Map<String, Long>> demandTypeMap = calculateAreaDemandByType(allAreas);

        // 3. 构建TreeNode列表
        List<TreeNode<String>> nodeList = buildDemandTypeTreeNodeList(allAreas, demandTypeMap);

        // 4. 构建树形结构
        return TreeUtil.build(nodeList, null);
    }

    /**
     * 计算所有地区的用户VIP数（核心修正：处理多结果集）
     */
    private Map<String, Long> calculateAreaUserVipCount(List<City> allAreas) {
        // 构建地区编码→地区对象的映射
        Map<String, City> areaMap = allAreas.stream()
                .collect(Collectors.toMap(City::getCode, area -> area));

        // 构建所有地区编码集合（用于设置默认值0）
        Set<String> allAreaCodes = allAreas.stream()
                .map(City::getCode)
                .collect(Collectors.toSet());

        // 2. 从用户表统计（修正：用List接收多条记录）
        List<Map<String, Object>> userAreaList = userVipTimeMapper.countVipByAreaCodes();
        // 转换为Map<String, Long>（核心修正：手动处理多结果）
        Map<String, Long> userAreaCount = new HashMap<>();
        for (Map<String, Object> item : userAreaList) {
            // 从Map中取出地区编码和计数（注意类型转换）
            String cityCode = (String) item.get("cityCode");
            Long count = ((Number) item.get("count")).longValue(); // 兼容Integer/Long/BigDecimal
            userAreaCount.put(cityCode, count);
        }

        // 3. 为所有地区设置默认值0（无用户的地区也会有计数）
        Map<String, Long> allAreaUserCount = new HashMap<>(allAreaCodes.size());
        for (String areaCode : allAreaCodes) {
            allAreaUserCount.put(areaCode, userAreaCount.getOrDefault(areaCode, 0L));
        }

        // 4. 筛选区县编码（通过编码长度判断，示例：6位为区县）
        List<String> countyCodes = allAreas.stream()
                .filter(area -> isCounty(area.getCode()))
                .map(City::getCode)
                .collect(Collectors.toList());

        // 5. 向上汇总：区县→市→省
        for (String countyCode : countyCodes) {
            Long count = allAreaUserCount.get(countyCode);
            String parentCode = areaMap.get(countyCode).getParentCode();
            accumulateToParent(parentCode, count, areaMap, allAreaUserCount);
        }

        return allAreaUserCount;
    }

    private List<TreeNode<String>> buildTreeNodeVipList(
            List<City> areas,
            Map<String, Long> areaUserCountMap,
            Map<String, Long> areaUserVipCountMap,
            Map<String, Long> provinceTotalMap,  // 缓存各省用户总数
            Long nationwideTotalUser) {  // 全国用户总数

        List<TreeNode<String>> nodeList = new ArrayList<>(areas.size());
        for (City area : areas) {
            TreeNode<String> node = new TreeNode<>(
                    area.getCode(),
                    area.getParentCode(),
                    area.getName(),
                    Integer.parseInt(area.getCode())
            );

            // 获取当前地区用户数
            Long userCount = areaUserCountMap.getOrDefault(area.getCode(), 0L);
            Long vipCount = areaUserVipCountMap.getOrDefault(area.getCode(), 0L);

            // 计算百分比（保留2位小数）
            BigDecimal percentage = calculatePercentage(
                    userCount,
                    area,
                    provinceTotalMap,
                    nationwideTotalUser
            );

            // 设置额外信息（包含百分比）
            Map<String, Object> extra = new HashMap<>(4);
            extra.put("userCount", userCount);
            extra.put("userVipCount", vipCount);
            extra.put("percentage", percentage);
            extra.put("percentageStr", percentage.setScale(2, RoundingMode.HALF_UP) + "%");
            node.setExtra(extra);

            nodeList.add(node);
        }
        return nodeList;
    }

    /**
     * 按层级计算百分比
     * - 省级：当前用户数 / 全国用户数
     * - 市/县级：当前用户数 / 所属省份用户数
     */
    private BigDecimal calculatePercentage(
            Long currentUserCount,
            City area,
            Map<String, Long> provinceTotalMap,
            Long nationwideTotalUser) {

        if (currentUserCount == 0) {
            return BigDecimal.ZERO;
        }

        // 判断是否为省级节点（父编码不在地区编码中即为省）
        boolean isProvince = StringUtils.isBlank(area.getParentCode())
                || !provinceTotalMap.containsKey(area.getParentCode());

        // 计算分母
        Long denominator = isProvince ? nationwideTotalUser :
                provinceTotalMap.getOrDefault(area.getParentCode(), 0L);

        if (denominator == 0) {
            return BigDecimal.ZERO;
        }

        // 计算百分比（保留4位小数用于后续格式化）
        return new BigDecimal(currentUserCount)
                .divide(new BigDecimal(denominator), 4, RoundingMode.HALF_UP)
                .multiply(new BigDecimal(100));
    }


    /**
     * 构建TreeNode列表
     */
    private List<TreeNode<String>> buildTreeNodeList(List<City> areas, Map<String, Long> userCountMap) {
        // 使用Java原生方法创建集合（避免Hutool依赖问题）
        List<TreeNode<String>> nodeList = new ArrayList<>(areas.size());
        for (City area : areas) {
            TreeNode<String> node = new TreeNode<>(
                    area.getCode(),
                    area.getParentCode(),
                    area.getName(),
                    Integer.parseInt(area.getCode())
            );

            // 设置用户数到extra
            Map<String, Object> extra = new HashMap<>(1);
            extra.put("userCount", userCountMap.get(area.getCode()));
            node.setExtra(extra);

            nodeList.add(node);
        }
        return nodeList;
    }

    /**
     * 递归向上汇总用户数
     */
    private void accumulateToParent(String currentParentCode, Long addCount,
                                    Map<String, City> areaMap, Map<String, Long> resultMap) {
        if (currentParentCode == null || "0".equals(currentParentCode) || !areaMap.containsKey(currentParentCode)) {
            return;
        }

        resultMap.put(currentParentCode, resultMap.get(currentParentCode) + addCount);
        String nextParentCode = areaMap.get(currentParentCode).getParentCode();
        accumulateToParent(nextParentCode, addCount, areaMap, resultMap);
    }

    /**
     * 判断是否为区县级（6位编码示例）
     */
    private boolean isCounty(String code) {
        return code != null && code.length() == 6;
    }

    /**
     * 查询附近的人
     *
     * @param currentUserId 当前用户IM ID
     * @param latitude      当前用户纬度
     * @param longitude     当前用户经度
     * @param radius        搜索半径（米，如1000表示1公里）
     * @return 附近用户列表（含IM用户信息）
     */
    public List<UserVO> getNearbyUsers(String currentUserId, double latitude, double longitude, int radius) {
        // 1. 调用LBS API查询附近的用户实体
        Map<String, String> params = new HashMap<>();
        params.put("key", lbsKey);
        params.put("table_id", "你的LBS数据表ID");
        params.put("location", longitude + "," + latitude); // 经纬度（注意顺序：经度,纬度）
        params.put("radius", String.valueOf(radius));
        params.put("page_size", "20"); // 每页数量

        OkHttpClient client = new OkHttpClient();
        HttpUrl.Builder urlBuilder = Objects.requireNonNull(Objects.requireNonNull(HttpUrl.parse(LBS_NEARBY_URL))).newBuilder();
        params.forEach(urlBuilder::addQueryParameter);
        Request request = new Request.Builder().url(urlBuilder.build()).get().build();

        try (Response response = client.newCall(request).execute()) {
            String result = response.body().string();
            JSONObject json = JSON.parseObject(result);
            if (json.getInteger("status") != 0) {
                throw new RuntimeException("附近用户查询失败：" + json.getString("message"));
            }

            // 2. 解析LBS返回的附近用户ID（entity_id即IM用户ID）
            JSONArray entities = json.getJSONObject("data").getJSONArray("entities");
            List<String> nearbyImUserIds = new ArrayList<>();
            for (Object entity : entities) {
                String imUserId = ((JSONObject) entity).getString("entity_id");
                if (!imUserId.equals(currentUserId)) { // 排除自己
                    nearbyImUserIds.add(imUserId);
                }
            }

            // 3. 调用腾讯IM API获取用户详情（昵称、头像等）
            return new ArrayList<>();
//                    imService. s(nearbyImUserIds).stream()
//                    .map(imUser -> {
//                        UserSimpleVO vo = new UserSimpleVO();
//                        vo.setName(imUser.getName());
//                        vo.setHeadImg(imUser.getI());
//                        // 可添加距离计算（根据经纬度差）
//                        return vo;
//                    }).collect(Collectors.toList());

        } catch (IOException e) {
            throw new RuntimeException("附近用户查询异常", e);
        }
    }

    /**
     * 计算所有地区的发帖数（含汇总逻辑）
     */
    private Map<String, Long> calculateAreaDemandCount(List<City> allAreas) {
        // 构建地区编码→地区对象的映射
        Map<String, City> areaMap = allAreas.stream()
                .collect(Collectors.toMap(City::getCode, area -> area));

        // 构建所有地区编码集合（用于设置默认值0）
        Set<String> allAreaCodes = allAreas.stream()
                .map(City::getCode)
                .collect(Collectors.toSet());

        // 从需求表统计发帖数
        List<Map<String, Object>> demandAreaList = demandService.countByAreaCodes();
        // 转换为Map<String, Long>
        Map<String, Long> demandAreaCount = new HashMap<>();
        for (Map<String, Object> item : demandAreaList) {
            String cityCode = (String) item.get("cityCode");
            Long count = ((Number) item.get("count")).longValue();
            demandAreaCount.put(cityCode, count);
        }

        // 为所有地区设置默认值0
        Map<String, Long> allAreaDemandCount = new HashMap<>(allAreaCodes.size());
        for (String areaCode : allAreaCodes) {
            allAreaDemandCount.put(areaCode, demandAreaCount.getOrDefault(areaCode, 0L));
        }

        // 筛选区县编码（通过编码长度判断）
        List<String> countyCodes = allAreas.stream()
                .filter(area -> isCounty(area.getCode()))
                .map(City::getCode)
                .collect(Collectors.toList());

        // 向上汇总：区县→市→省
        for (String countyCode : countyCodes) {
            Long count = allAreaDemandCount.get(countyCode);
            String parentCode = areaMap.get(countyCode).getParentCode();
            accumulateToParent(parentCode, count, areaMap, allAreaDemandCount);
        }

        return allAreaDemandCount;
    }

    /**
     * 构建包含发帖数的TreeNode列表
     */
    private List<TreeNode<String>> buildTreeNodeDemandList(List<City> areas, Map<String, Long> demandCountMap) {
        List<TreeNode<String>> nodeList = new ArrayList<>(areas.size());
        for (City area : areas) {
            TreeNode<String> node = new TreeNode<>(
                    area.getCode(),
                    area.getParentCode(),
                    area.getName(),
                    Integer.parseInt(area.getCode())
            );

            // 设置发帖数到extra
            Map<String, Object> extra = new HashMap<>(1);
            extra.put("demandCount", demandCountMap.get(area.getCode()));
            node.setExtra(extra);

            nodeList.add(node);
        }
        return nodeList;
    }

    @Service
    public class LocationService {
        // 腾讯LBS云存储API地址（存储用户位置）
        private static final String LBS_STORAGE_URL = "https://apis.map.qq.com/ws/geodata/v1/entity/add";
        private final String lbsKey = "你的腾讯LBS密钥"; // 从腾讯位置服务控制台获取

        /**
         * 上报用户地理位置
         *
         * @param imUserId  腾讯IM用户ID（与IM体系绑定）
         * @param latitude  纬度
         * @param longitude 经度
         */
        public void reportLocation(String imUserId, double latitude, double longitude) {
            // 1. 构建LBS云存储请求参数（存储用户ID、经纬度、时间戳等）
            Map<String, String> params = new HashMap<>();
            params.put("key", lbsKey);
            params.put("table_id", "你的LBS数据表ID");               // 需在LBS控制台创建数据表
            params.put("entity_id", imUserId);                      // 用IM用户ID作为唯一标识
            params.put("latitude", String.valueOf(latitude));
            params.put("longitude", String.valueOf(longitude));
            params.put("timestamp", String.valueOf(System.currentTimeMillis() / 1000));

            // 2. 调用腾讯LBS API存储位置
            OkHttpClient client = new OkHttpClient();
            FormBody.Builder formBuilder = new FormBody.Builder();
            params.forEach(formBuilder::add);
            Request request = new Request.Builder()
                    .url(LBS_STORAGE_URL)
                    .post(formBuilder.build())
                    .build();

            try (Response response = client.newCall(request).execute()) {
                String result = response.body().string();
                // 3. 解析响应，判断是否存储成功
                if (!result.contains("\"status\":0")) {
                    throw new RuntimeException("位置上报失败：" + result);
                }
            } catch (IOException e) {
                throw new RuntimeException("位置上报异常", e);
            }
        }
    }
}